import type { SqlCommenterContext, SqlCommenterPlugin } from '@prisma/sqlcommenter'

/**
 * Formats key-value pairs into a sqlcommenter-compatible comment string.
 *
 * Algorithm per https://google.github.io/sqlcommenter/spec/:
 * 1. If the map is empty, return empty string
 * 2. Sort keys lexicographically
 * 3. URL-encode keys
 * 4. URL-encode values
 * 5. Replace ' with \' in values (after URL encoding)
 * 6. Wrap values in single quotes
 * 7. Join key='value' pairs with commas
 * 8. Wrap in /* *\/
 */
export function formatSqlComment(tags: Record<string, string>): string {
  const entries = Object.entries(tags)
  if (entries.length === 0) {
    return ''
  }

  // Sort by key lexicographically
  entries.sort(([a], [b]) => a.localeCompare(b))

  const parts = entries.map(([key, value]) => {
    const encodedKey = encodeURIComponent(key)
    const encodedValue = encodeURIComponent(value).replace(/'/g, "\\'")
    return `${encodedKey}='${encodedValue}'`
  })

  return `/*${parts.join(',')}*/`
}

/**
 * Applies SQL commenter plugins and returns the merged key-value pairs.
 * Keys with undefined values are filtered out.
 */
export function applySqlCommenters(
  plugins: SqlCommenterPlugin[],
  context: SqlCommenterContext,
): Record<string, string> {
  const merged: Record<string, string> = {}

  for (const plugin of plugins) {
    const tags = plugin(context)
    for (const [key, value] of Object.entries(tags)) {
      if (value !== undefined) {
        merged[key] = value
      }
    }
  }

  return merged
}

/**
 * Applies SQL commenter plugins and returns the formatted comment.
 */
export function buildSqlComment(plugins: SqlCommenterPlugin[], context: SqlCommenterContext): string {
  const tags = applySqlCommenters(plugins, context)
  return formatSqlComment(tags)
}

/**
 * Appends a sqlcommenter comment to a SQL query.
 */
export function appendSqlComment(sql: string, comment: string): string {
  if (!comment) {
    return sql
  }
  return `${sql} ${comment}`
}
